<template>
  <view class="page">
    <view class="canvas-box">
      <canvas 
        canvas-id="myChart"
        :style="{ width: canvasW + 'px', height: canvasH + 'px' }"
        @touchstart="touchstart"
      ></canvas>
    </view>
  </view>
</template>

<script>
export default {
  data() {
    return {
      canvasW: 0,
      canvasH: 300,
      ctx: null,
      colorList: ['#6EBA44'],
      axisInfo: null,
      tooltipIndex: -1, // tooltip显示的x轴索引
      option: {
        xAxis: { data: ['10/15', '10/16', '10/17', '10/18', '10/19', '10/20', '10/21'] },
        series: [
          { name: '', data: [2, 4, 6, 2,1,5, 6] },
        ]
      }
    };
  },
  mounted() {
    this.$nextTick(() => {
      const sys = uni.getSystemInfoSync();
      this.canvasW = sys.windowWidth;
      this.canvasH = 300;
      this.ctx = uni.createCanvasContext('myChart', this)
      this.updateCanvas();
    });
  },
  methods: {
    updateCanvas() {
      this.ctx.clearRect(0, 0, this.canvasW, this.canvasH);

      this.setTitle();       // 标题
      this.initAxis();       // 坐标初始化
      this.drawAxis();       // 画坐标轴
      if (this.tooltipIndex >= 0) {
        this.drawTooltipBackground(this.tooltipIndex); // 背景在折线下面
      }
      this.drawSeries();     // 折线和节点
      if (this.tooltipIndex >= 0) {
        this.drawTooltipText(this.tooltipIndex);      // 数字和 x 轴信息
      }

      this.ctx.draw();
    },

    setTitle() {
      const ctx = this.ctx;
      const { title } = this.option;
      if (title?.text) {
        ctx.setFontSize(16);
        ctx.setFillStyle('#ff007f');
        ctx.fillText(title.text, 10, 10);
      }
      if (title?.subText) {
        ctx.setFontSize(12);
        ctx.setFillStyle('#7d7d7d');
        ctx.fillText(title.subText, 10, 30);
      }
    },

    initAxis() {
      const { series, xAxis } = this.option;
      const padding = 40;
      const contentW = this.canvasW - padding * 2;
      const contentH = this.canvasH - padding * 2;

      let values = [0];
      series.forEach(s => values = values.concat(s.data));
      const max = Math.max(...values);
      const min = Math.min(...values);

      const yStep = contentH / (max - min || 1);
	  

      this.axisInfo = { padding, contentW, contentH, xCount: xAxis.data.length, yStep, max, min };
    },

    drawAxis() {
      const ctx = this.ctx;
      const { padding, contentW, xCount, yStep, max, min } = this.axisInfo;

      // x轴文字
      this.option.xAxis.data.forEach((txt, i) => {
        ctx.setFontSize(12);
        ctx.setFillStyle('#888');
        ctx.setTextAlign('center');
        const xStep = contentW / xCount;
        ctx.fillText(txt, padding + xStep * i + xStep / 2, this.canvasH - padding + 14);
      });

      // y轴虚线及文字
      const yCount = 5;
      for (let i = 0; i <= yCount; i++) {
        const val = min + ((max - min) / yCount) * i;
        const y = padding + (max - val) * yStep;

        if (val !== 0) {
          ctx.beginPath();
          ctx.setStrokeStyle('#e1e7ee');
          ctx.setLineWidth(1);
          ctx.setLineDash([5, 5]);
          ctx.moveTo(padding, y);
          ctx.lineTo(this.canvasW - padding, y);
          ctx.stroke();
          ctx.setLineDash([]);
        }

        ctx.setFontSize(10);
        ctx.setFillStyle('#888');
        ctx.setTextAlign('right');
        ctx.fillText(val.toFixed(0), padding - 5, y);
      }
    },
	

    drawSeries() {
      const ctx = this.ctx;
      const { series } = this.option;
      const { padding, contentW, xCount, yStep, max } = this.axisInfo;
      const xStep = contentW / xCount;

      series.forEach((s, si) => {
        // 折线
        ctx.beginPath();
        ctx.setStrokeStyle(s.lineStyle?.color || this.colorList[si]);
        ctx.setLineWidth(s.lineStyle?.width || 2);

        s.data.forEach((val, i) => {
          const x = padding + xStep * i + xStep / 2;
          const y = padding + (max - val) * yStep;
          if (i === 0) ctx.moveTo(x, y);
          else ctx.lineTo(x, y);
        });
        ctx.stroke();

        // 节点
        s.data.forEach((val, i) => {
          const x = padding + xStep * i + xStep / 2;
          const y = padding + (max - val) * yStep;
          ctx.beginPath();
          ctx.arc(x, y, 3, 0, 2 * Math.PI);
          ctx.setFillStyle('#fff');
          ctx.fill();
          ctx.stroke();
        });
      });
    },

    drawTooltipBackground(index) {
      const ctx = this.ctx;
      const { padding, contentW, contentH, xCount } = this.axisInfo;
      const xStep = contentW / xCount;
      const rectX = padding + xStep * (index - 1);
      const rectY = padding; // 顶部
      const rectW = xStep;   // 背景覆盖单个 x 轴单元
      const rectH = contentH;

      ctx.setFillStyle('#f5f5f5');
      ctx.setGlobalAlpha(0.5);
      ctx.fillRect(rectX, rectY, rectW, rectH);
      ctx.setGlobalAlpha(1);
    },

    drawTooltipText(index) {
      const ctx = this.ctx;
      const { series, xAxis } = this.option;
      const { padding, contentW, xCount } = this.axisInfo;
      const xStep = contentW / xCount;
      const rectX = padding + xStep * (index - 1);
      const rectY = padding;

      // x 轴信息
      ctx.setFillStyle('#6EBA44');
      ctx.setFontSize(12);
      ctx.setTextAlign('left');
      ctx.setTextBaseline('top');
      const xText = xAxis.data[index - 1] || '';
      ctx.fillText(xText, rectX + 5, rectY + 5);

      // 数据数字
      series.forEach((s, i) => {
        const val = s.data[index - 1];
        ctx.setFillStyle('#000');
        ctx.setFontSize(12);
        ctx.fillText(`${val}`, rectX + 5, rectY + 25 + i * 20);
      });
    },

    touchstart(e) {
      const touchX = e.touches[0].x;
      const { padding, contentW, xCount } = this.axisInfo;
      const xStep = contentW / xCount;
      const index = Math.floor((touchX - padding) / xStep) + 1;
      if (index < 1 || index > xCount) return;
      this.tooltipIndex = index;
      this.updateCanvas();
      setTimeout(() => {
        this.tooltipIndex = -1;
        this.updateCanvas();
      }, 2000);
    }
  }
};
</script>

<style scoped>
.canvas-box {
  width: 100%;
  height: 300px;
 /* background: #f5f5f5; */
}
.page {
  padding: 0;
}
</style>
